package cn.jbolt.ai.core.chain.node.action.funccall;

import cn.hutool.core.util.StrUtil;
import cn.jbolt.ai.core.chain.node.base.AppConfigConstant;
import cn.jbolt.ai.core.chain.ChainContext;
import cn.jbolt.ai.core.chain.node.base.LlmConfig;
import cn.jbolt.ai.core.chain.node.base.BaseNode;
import cn.jbolt.ai.core.chain.node.provider.CaseNodeProvider;
import cn.jbolt.ai.core.func.FunctionCallResult;
import cn.jbolt.ai.core.func.NativeFunctionCall;
import cn.jbolt.ai.resource.function.entity.AiFunctionResource;
import cn.jbolt.util.JSONUtil;
import cn.jbolt.util.Result;
import com.fasterxml.jackson.databind.JsonNode;
import com.jboltai.capability.model.JBoltAI;
import com.jboltai.event.EventErrorType;
import com.jboltai.event.ai.aifunccall.AIFuncCallEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


@Component
public class FuncCallNodeProvider extends BaseNode implements CaseNodeProvider {

    private static final Logger logger = LoggerFactory.getLogger(FuncCallNodeProvider.class);

    public String provide(JsonNode nodeConfig, ChainContext context) {
        AIFuncCallEvent event = JBoltAI.funcCall();
        LlmConfig llmConfig = LlmConfig.from(nodeConfig.get(AppConfigConstant.CONFIG_TYPE_LLM));
        FuncCallNodeConfig funcCallConfig = FuncCallNodeConfig.from(nodeConfig.get(AppConfigConstant.CONFIG_TYPE_FUNCCALL));
        if (funcCallConfig.getFunctions() == null || funcCallConfig.getFunctions().length == 0) {
            logger.error("FuncCallNodeProvider process 异常,异常原因: 未绑定Function资源");
            if (funcCallConfig.isOutputToResponse()) {
                context.sendErrorMsg("未绑定Function资源");


            }
//            throw new RuntimeException("未绑定Function资源");
            return AppConfigConstant.AFTER_KEY_FUNC_NO_MATCH;
        }
        //根据配置初始化event
        configEvent(llmConfig, funcCallConfig, context, event);
        event.publish().await();

        if (event.isFail()) {

            if (event.getError() != null && event.getError().getErrorType() == EventErrorType.NO_FUNCTION_CALL_MATCH) {
                return AppConfigConstant.AFTER_KEY_FUNC_NO_MATCH;
            }
            //事件发生异常
            logger.error("FuncCall节点执行中发生异常,异常原因", event.getError().getException());
            throw new RuntimeException(event.getError().getMsg());
        }

        if (event.isSuccess()) {
            if (funcCallConfig.isOutputToResponse()) {
                //如果配置项要求 内容返回到响应里，那就输出
                //构建相应信息
                context.sendSuccessMsgTip("匹配到Function资源：" + event.getResult().getFunction());
                context.sendInfoMsgTip("正在执行Function,获取结果...");
            }

            Result<FunctionCallResult> result = NativeFunctionCall.call(event.getResult(), event, context);
            if (result.isError()) {
                if (funcCallConfig.isOutputToResponse()) {
                    context.sendErrorMsg("Function执行过程中发生异常：" + result.getMsg());
                }
                throw new RuntimeException("Function执行过程中发生异常：" + result.getMsg());
            } else {
                if (funcCallConfig.isOutputToResponse()) {
                    context.sendSuccessMsgTip("Function执行成功");
                }
                if (StrUtil.isNotBlank(funcCallConfig.getResultOutputField())) {
                    //配置项要求，把结果输出到上下文
                    context.setAttr(funcCallConfig.getResultOutputField(), result.getData().getResult());
                }
                if (StrUtil.isNotBlank(funcCallConfig.getMatchFuncOutputField())) {
                    //配置项要求，把匹配的function输出到上下文
                    AiFunctionResource functionResource = result.getData().getFunctionResource();
                    context.setAttr(funcCallConfig.getMatchFuncOutputField(),
                            JSONUtil.createObjectNode().put("sn", functionResource.getSn()).put("description", functionResource.getBriefInfo())
                    );
                }
            }
            return AppConfigConstant.AFTER_KEY_FUNC_CALL_SUCCESS;
        }

        return "";


    }

    private void configEvent(LlmConfig llmConfig, FuncCallNodeConfig funcCallConfig, ChainContext context, AIFuncCallEvent event) {
        event.bindFunctionResourceByIds(funcCallConfig.getFunctions());
        super.configLlm(llmConfig, context, event);
    }


}
